/**
 * src/utils/scheduledTasks.ts
 * ------------------------------------
 * 定时任务管理器
 * 1. ScheduledTasks：定时任务调度、执行、管理
 * 2. 积分过期检查：每日检查并处理过期积分
 * 3. 厨师状态检查：定期检查厨师在线状态
 * 4. 通知清理：定期清理过期通知
 * 5. 生日奖励：检查用户生日并发放奖励
 * 支持手动执行和自动调度，确保系统数据及时更新
 * 创建日期：2025-08-06
 */
import Taro from '@tarojs/taro'
import { pointsUtils } from './pointsUtils'
import { CloudDataManager } from './cloud'
import { errorUtils, ErrorType } from './errorHandler'
import { TimerManager } from './timerManager'

/**
 * 上次执行时间的存储键
 * 用于记录各任务的上次执行时间，避免重复执行
 */
const LAST_EXECUTION_KEY = {
  EXPIRE_POINTS: 'last_expire_points_check',
  CHEF_STATUS: 'last_chef_status_check',
  NOTIFICATION_CLEANUP: 'last_notification_cleanup'
}

/**
 * 执行间隔配置（毫秒）
 * 定义各任务的执行频率
 */
const EXECUTION_INTERVAL = {
  EXPIRE_POINTS: 24 * 60 * 60 * 1000, // 每24小时
  CHEF_STATUS: 30 * 60 * 1000, // 每30分钟
  NOTIFICATION_CLEANUP: 7 * 24 * 60 * 60 * 1000 // 每7天
}

/**
 * 定时任务管理器
 * 负责调度和执行各种系统维护任务
 * 包括积分过期检查、厨师状态检查、通知清理等
 */
export class ScheduledTasks {
  /**
   * 初始化所有定时任务
   * 启动所有预定义的定时任务，确保系统正常运行
   */
  static init(): void {
    console.log('初始化定时任务管理器')
    
    // 清理可能存在的旧定时器
    TimerManager.clearAll()
    
    try {
      // 启动积分过期检查任务
      this.scheduleTask(
        'expire_points_check',
        LAST_EXECUTION_KEY.EXPIRE_POINTS,
        EXECUTION_INTERVAL.EXPIRE_POINTS,
        async () => {
          try {
            const expiredCount = await pointsUtils.processExpiredPoints()
            console.log(`处理了 ${expiredCount} 个过期积分`)
            return true
          } catch (error) {
            console.error('积分过期处理失败:', error)
            return false
          }
        }
      )

      // 启动厨师状态检查任务
      this.scheduleTask(
        'chef_status_check',
        LAST_EXECUTION_KEY.CHEF_STATUS,
        EXECUTION_INTERVAL.CHEF_STATUS,
        async () => {
          try {
            return await this.checkChefStatus()
          } catch (error) {
            console.error('厨师状态检查失败:', error)
            return false
          }
        }
      )

      // 启动通知清理任务
      this.scheduleTask(
        'notification_cleanup',
        LAST_EXECUTION_KEY.NOTIFICATION_CLEANUP,
        EXECUTION_INTERVAL.NOTIFICATION_CLEANUP,
        async () => {
          try {
            // 获取30天前的时间
            const cutoffDate = new Date()
            cutoffDate.setDate(cutoffDate.getDate() - 30)
            
            // 查找30天前的已读通知
            const oldNotifications = await CloudDataManager.getAllData('notifications', {
              isRead: true,
              createdAt: { $lt: cutoffDate }
            })
            
            // 批量删除
            for (const notification of oldNotifications) {
              await CloudDataManager.deleteData('notifications', notification.id)
            }
            
            console.log(`清理了 ${oldNotifications.length} 条过期通知`)
            return true
          } catch (error) {
            console.error('通知清理失败:', error)
            return false
          }
        }
      )

      console.log('定时任务初始化完成')
    } catch (error) {
      console.error('定时任务初始化失败:', error)
    }
  }

  /**
   * 清理所有定时任务
   */
  static cleanup(): void {
    console.log('清理所有定时任务')
    TimerManager.clearAll()
  }

  /**
   * 安排积分过期检查任务
   * 每日检查并处理过期的积分，发送过期通知
   */
  static schedulePointsExpiration(): void {
    this.scheduleTask(
      LAST_EXECUTION_KEY.EXPIRE_POINTS,
      EXECUTION_INTERVAL.EXPIRE_POINTS,
      async () => {
        console.log('执行积分过期检查...')
        try {
          const expiredCount = await pointsUtils.processExpiredPoints()
          console.log(`处理了 ${expiredCount} 个过期积分`)
          
          // 如果有积分过期，发送通知
          if (expiredCount > 0) {
            // 获取所有有过期积分的用户
            const today = new Date()
            today.setHours(0, 0, 0, 0)
            
            const expirations = await CloudDataManager.getAllData('points_expirations', {
              isExpired: true,
              // 查找今天过期的记录
              updatedAt: { $gte: today }
            })
            
            // 按用户分组
            const userExpirations = {}
            expirations.forEach(exp => {
              if (!userExpirations[exp.userId]) {
                userExpirations[exp.userId] = []
              }
              userExpirations[exp.userId].push(exp)
            })
            
            // 为每个用户发送通知
            for (const userId in userExpirations) {
              const totalExpired = userExpirations[userId].reduce((sum, exp) => sum + exp.points, 0)
              
              // 添加通知
              await CloudDataManager.addData('notifications', {
                userId,
                title: '积分过期提醒',
                content: `您有${totalExpired}积分已过期`,
                type: 'points_expired',
                isRead: false,
                createdAt: new Date()
              })
            }
          }
          
          return true
        } catch (error) {
          console.error('积分过期处理失败:', error)
          errorUtils.handleError(error, ErrorType.TASK, {
            operation: 'processExpiredPoints'
          })
          return false
        }
      }
    )
  }

  /**
   * 安排厨师状态检查任务
   */
  static scheduleChefStatusCheck(): void {
    this.scheduleTask(
      LAST_EXECUTION_KEY.CHEF_STATUS,
      EXECUTION_INTERVAL.CHEF_STATUS,
      async () => {
        console.log('执行厨师状态检查...')
        try {
          await this.checkChefStatus()
          return true
        } catch (error) {
          console.error('厨师状态检查失败:', error)
          errorUtils.handleError(error, ErrorType.TASK, {
            operation: 'checkChefStatus'
          })
          return false
        }
      }
    )
  }
  
  /**
   * 检查厨师状态
   * @returns Promise<number> 更新的厨师数量
   */
  static async checkChefStatus(): Promise<number> {
    try {
      // 获取所有厨师
      const chefs = await CloudDataManager.getAllData('users', { role: 'chef' })
      console.log(`获取到 ${chefs.length} 个厨师用户`)
      
      // 检查每个厨师的最后活跃时间
      const now = Date.now()
      const inactiveThreshold = 2 * 60 * 60 * 1000 // 2小时不活跃视为离线
      
      let updatedCount = 0
      
      for (const chef of chefs) {
        console.log(`检查厨师: ${chef.name}, ID: ${chef.id}, 状态: ${chef.status}`)
        
        // 如果厨师已经是离线状态，跳过
        if (chef.status === 'offline') continue
        
        // 检查是否有有效的ID
        if (!chef.id || chef.id.trim() === '') {
          console.warn(`厨师 ${chef.name} 缺少有效ID，跳过状态更新`)
          continue
        }
        
        // 检查最后活跃时间
        const lastActiveAt = chef.lastActiveAt ? new Date(chef.lastActiveAt).getTime() : 0
        if (now - lastActiveAt > inactiveThreshold) {
          // 更新为离线状态
          await CloudDataManager.updateData('users', chef.id, {
            status: 'offline',
            updatedAt: new Date()
          })
          
          updatedCount++
          console.log(`厨师 ${chef.name} 已自动设置为离线状态`)
        }
      }
      
      return updatedCount
    } catch (error) {
      console.error('厨师状态检查失败:', error)
      throw error
    }
  }

  /**
   * 安排通知清理任务
   */
  static scheduleNotificationCleanup(): void {
    this.scheduleTask(
      LAST_EXECUTION_KEY.NOTIFICATION_CLEANUP,
      EXECUTION_INTERVAL.NOTIFICATION_CLEANUP,
      async () => {
        console.log('执行通知清理...')
        try {
          // 获取30天前的时间
          const cutoffDate = new Date()
          cutoffDate.setDate(cutoffDate.getDate() - 30)
          
          // 查找30天前的已读通知
          const oldNotifications = await CloudDataManager.getAllData('notifications', {
            isRead: true,
            createdAt: { $lt: cutoffDate }
          })
          
          // 批量删除
          for (const notification of oldNotifications) {
            await CloudDataManager.deleteData('notifications', notification.id)
          }
          
          console.log(`清理了 ${oldNotifications.length} 条旧通知`)
          
          // 记录日志
          await CloudDataManager.addData('system_logs', {
            operation: 'notification_cleanup',
            details: `清理了 ${oldNotifications.length} 条旧通知`,
            createdAt: new Date()
          })
          
          return true
        } catch (error) {
          console.error('通知清理失败:', error)
          errorUtils.handleError(error, ErrorType.TASK, {
            operation: 'cleanupNotifications'
          })
          return false
        }
      }
    )
  }

  /**
   * 安排生日奖励检查任务
   */
  static scheduleBirthdayRewards(): void {
    // 每天凌晨1点执行一次
    const checkTime = new Date()
    checkTime.setHours(1, 0, 0, 0)
    
    const now = new Date()
    let delay = checkTime.getTime() - now.getTime()
    
    // 如果今天的检查时间已经过了，设置为明天的检查时间
    if (delay < 0) {
      delay += 24 * 60 * 60 * 1000
    }
    
    // 设置定时器
    setTimeout(() => {
      this.processBirthdayRewards()
      
      // 之后每24小时执行一次
      setInterval(() => {
        this.processBirthdayRewards()
      }, 24 * 60 * 60 * 1000)
    }, delay)
  }

  /**
   * 处理生日奖励
   */
  static async processBirthdayRewards(): Promise<void> {
    console.log('执行生日奖励检查...')
    
    try {
      // 获取当前日期（月和日）
      const today = new Date()
      const currentMonth = today.getMonth() + 1
      const currentDay = today.getDate()
      
      // 查找所有设置了生日的用户
      const users = await CloudDataManager.getAllData('users', {
        birthday: { $exists: true }
      })
      
      let rewardedCount = 0
      
      // 检查每个用户的生日
      for (const user of users) {
        if (!user.birthday) continue
        
        const birthday = new Date(user.birthday)
        const birthMonth = birthday.getMonth() + 1
        const birthDay = birthday.getDate()
        
        // 如果今天是用户的生日
        if (currentMonth === birthMonth && currentDay === birthDay) {
          // 检查是否已经发放过今年的生日奖励
          const currentYear = today.getFullYear()
          const lastRewardYear = user.lastBirthdayRewardYear || 0
          
          if (lastRewardYear < currentYear) {
            // 根据会员等级确定奖励积分
            const memberLevel = user.memberLevel || 1
            let rewardPoints = 100 // 基础奖励
            
            // 会员等级越高，奖励越多
            switch (memberLevel) {
              case 2:
                rewardPoints = 200
                break
              case 3:
                rewardPoints = 300
                break
              case 4:
                rewardPoints = 500
                break
            }
            
            // 发放生日奖励积分
            await pointsUtils.addPoints(
              user.id,
              rewardPoints,
              'activity_reward',
              `生日特别奖励`,
              'birthday_reward'
            )
            
            // 更新用户的最后生日奖励年份
            await CloudDataManager.updateData('users', user.id, {
              lastBirthdayRewardYear: currentYear,
              updatedAt: new Date()
            })
            
            // 发送生日祝福通知
            await CloudDataManager.addData('notifications', {
              userId: user.id,
              title: '生日快乐',
              content: `今天是您的生日，我们为您准备了${rewardPoints}积分的生日礼物，祝您生日快乐！`,
              type: 'birthday',
              isRead: false,
              createdAt: new Date()
            })
            
            rewardedCount++
          }
        }
      }
      
      console.log(`已处理 ${rewardedCount} 个生日奖励`)
    } catch (error) {
      console.error('处理生日奖励失败:', error)
      errorUtils.handleError(error, ErrorType.TASK, {
        operation: 'processBirthdayRewards'
      })
    }
  }

  /**
   * 安排定时任务
   * @param timerId 定时器唯一标识
   * @param lastExecutionKey 上次执行时间的存储键
   * @param interval 执行间隔（毫秒）
   * @param task 任务函数
   */
  private static scheduleTask(
    timerId: string,
    lastExecutionKey: string,
    interval: number,
    task: () => Promise<boolean>
  ): void {
    // 获取上次执行时间
    const lastExecution = Taro.getStorageSync(lastExecutionKey) || 0
    const now = Date.now()
    
    // 如果从未执行过或已经超过间隔时间，立即执行
    if (lastExecution === 0 || now - lastExecution >= interval) {
      this.executeTask(lastExecutionKey, task)
    }
    
    // 设置定期检查，使用TimerManager管理
    TimerManager.setInterval(timerId, () => {
      const lastExecution = Taro.getStorageSync(lastExecutionKey) || 0
      const now = Date.now()
      
      if (now - lastExecution >= interval) {
        this.executeTask(lastExecutionKey, task)
      }
    }, 60000) // 每分钟检查一次
  }

  /**
   * 执行任务并更新上次执行时间
   * @param lastExecutionKey 上次执行时间的存储键
   * @param task 任务函数
   */
  private static async executeTask(
    lastExecutionKey: string,
    task: () => Promise<boolean>
  ): Promise<void> {
    try {
      const success = await task()
      
      if (success) {
        // 更新上次执行时间
        Taro.setStorageSync(lastExecutionKey, Date.now())
      }
    } catch (error) {
      console.error(`任务执行失败 (${lastExecutionKey}):`, error)
    }
  }
  
  /**
   * 手动执行积分过期检查
   * @returns Promise<number> 处理的过期积分数量
   */
  static async manualCheckPointsExpiration(): Promise<number> {
    try {
      const expiredCount = await pointsUtils.processExpiredPoints()
      
      // 更新上次执行时间
      Taro.setStorageSync(LAST_EXECUTION_KEY.EXPIRE_POINTS, Date.now())
      
      return expiredCount
    } catch (error) {
      console.error('手动执行积分过期检查失败:', error)
      throw error
    }
  }
  
  /**
   * 手动执行通知清理
   * @returns Promise<number> 清理的通知数量
   */
  static async manualCleanupNotifications(): Promise<number> {
    try {
      // 获取30天前的时间
      const cutoffDate = new Date()
      cutoffDate.setDate(cutoffDate.getDate() - 30)
      
      // 查找30天前的已读通知
      const oldNotifications = await CloudDataManager.getAllData('notifications', {
        isRead: true,
        createdAt: { $lt: cutoffDate }
      })
      
      // 批量删除
      for (const notification of oldNotifications) {
        await CloudDataManager.deleteData('notifications', notification.id)
      }
      
      // 更新上次执行时间
      Taro.setStorageSync(LAST_EXECUTION_KEY.NOTIFICATION_CLEANUP, Date.now())
      
      return oldNotifications.length
    } catch (error) {
      console.error('手动执行通知清理失败:', error)
      throw error
    }
  }

  /**
   * 手动执行生日奖励检查
   * @returns Promise<number> 处理的用户数量
   */
  static async manualCheckBirthdayRewards(): Promise<number> {
    try {
      // 获取当前日期（月和日）
      const today = new Date()
      const currentMonth = today.getMonth() + 1
      const currentDay = today.getDate()
      
      // 查找所有设置了生日的用户
      const users = await CloudDataManager.getAllData('users', {
        birthday: { $exists: true }
      })
      
      let rewardedCount = 0
      
      // 检查每个用户的生日
      for (const user of users) {
        if (!user.birthday) continue
        
        const birthday = new Date(user.birthday)
        const birthMonth = birthday.getMonth() + 1
        const birthDay = birthday.getDate()
        
        // 如果今天是用户的生日
        if (currentMonth === birthMonth && currentDay === birthDay) {
          // 检查是否已经发放过今年的生日奖励
          const currentYear = today.getFullYear()
          const lastRewardYear = user.lastBirthdayRewardYear || 0
          
          if (lastRewardYear < currentYear) {
            // 根据会员等级确定奖励积分
            const memberLevel = user.memberLevel || 1
            let rewardPoints = 100 // 基础奖励
            
            // 会员等级越高，奖励越多
            switch (memberLevel) {
              case 2:
                rewardPoints = 200
                break
              case 3:
                rewardPoints = 300
                break
              case 4:
                rewardPoints = 500
                break
            }
            
            // 发放生日奖励积分
            await pointsUtils.addPoints(
              user.id,
              rewardPoints,
              'activity_reward',
              `生日特别奖励`,
              'birthday_reward'
            )
            
            // 更新用户的最后生日奖励年份
            await CloudDataManager.updateData('users', user.id, {
              lastBirthdayRewardYear: currentYear,
              updatedAt: new Date()
            })
            
            // 发送生日祝福通知
            await CloudDataManager.addData('notifications', {
              userId: user.id,
              title: '生日快乐',
              content: `今天是您的生日，我们为您准备了${rewardPoints}积分的生日礼物，祝您生日快乐！`,
              type: 'birthday',
              isRead: false,
              createdAt: new Date()
            })
            
            rewardedCount++
          }
        }
      }
      
      return rewardedCount
    } catch (error) {
      console.error('手动执行生日奖励检查失败:', error)
      throw error
    }
  }
}

// 导出实例
export const scheduledTasks = {
  init: ScheduledTasks.init.bind(ScheduledTasks),
  cleanup: ScheduledTasks.cleanup.bind(ScheduledTasks),
  checkChefStatus: ScheduledTasks.checkChefStatus.bind(ScheduledTasks),
  manualCheckPointsExpiration: ScheduledTasks.manualCheckPointsExpiration.bind(ScheduledTasks),
  manualCleanupNotifications: ScheduledTasks.manualCleanupNotifications.bind(ScheduledTasks),
  manualCheckBirthdayRewards: ScheduledTasks.manualCheckBirthdayRewards.bind(ScheduledTasks)
} 